﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Algorithm;
using NetTopologySuite.Geometries;
using NetTopologySuite.GeometriesGraph;

namespace NetTopologySuite.Operation.Buffer
{
	internal class SubgraphDepthLocater
	{
		public SubgraphDepthLocater(IList<BufferSubgraph> subgraphs)
		{
			this._subgraphs = subgraphs;
		}

		public int GetDepth(Coordinate p)
		{
			List<SubgraphDepthLocater.DepthSegment> list = new List<SubgraphDepthLocater.DepthSegment>(this.FindStabbedSegments(p));
			if (list.Count == 0)
			{
				return 0;
			}
			list.Sort();
			return list[0].LeftDepth;
		}

		private IList<SubgraphDepthLocater.DepthSegment> FindStabbedSegments(Coordinate stabbingRayLeftPt)
		{
			IList<SubgraphDepthLocater.DepthSegment> list = new List<SubgraphDepthLocater.DepthSegment>();
			foreach (BufferSubgraph bufferSubgraph in this._subgraphs)
			{
				this.FindStabbedSegments(stabbingRayLeftPt, bufferSubgraph.DirectedEdges, list);
			}
			return list;
		}

		private void FindStabbedSegments(Coordinate stabbingRayLeftPt, IEnumerable<DirectedEdge> dirEdges, IList<SubgraphDepthLocater.DepthSegment> stabbedSegments)
		{
			foreach (DirectedEdge directedEdge in dirEdges)
			{
				if (directedEdge.IsForward)
				{
					this.FindStabbedSegments(stabbingRayLeftPt, directedEdge, stabbedSegments);
				}
			}
		}

		private void FindStabbedSegments(Coordinate stabbingRayLeftPt, DirectedEdge dirEdge, IList<SubgraphDepthLocater.DepthSegment> stabbedSegments)
		{
			Coordinate[] coordinates = dirEdge.Edge.Coordinates;
			for (int i = 0; i < coordinates.Length - 1; i++)
			{
				this._seg.P0 = coordinates[i];
				this._seg.P1 = coordinates[i + 1];
				if (this._seg.P0.Y > this._seg.P1.Y)
				{
					this._seg.Reverse();
				}
				if (System.Math.Max(this._seg.P0.X, this._seg.P1.X) >= stabbingRayLeftPt.X && !this._seg.IsHorizontal && stabbingRayLeftPt.Y >= this._seg.P0.Y && stabbingRayLeftPt.Y <= this._seg.P1.Y && CGAlgorithms.ComputeOrientation(this._seg.P0, this._seg.P1, stabbingRayLeftPt) != -1)
				{
					int depth = dirEdge.GetDepth(Positions.Left);
					if (!this._seg.P0.Equals(coordinates[i]))
					{
						depth = dirEdge.GetDepth(Positions.Right);
					}
					SubgraphDepthLocater.DepthSegment item = new SubgraphDepthLocater.DepthSegment(this._seg, depth);
					stabbedSegments.Add(item);
				}
			}
		}

		private readonly IList<BufferSubgraph> _subgraphs;

		private readonly LineSegment _seg = new LineSegment();

		internal class DepthSegment : IComparable<SubgraphDepthLocater.DepthSegment>
		{
			public int LeftDepth { get; set; }

			public DepthSegment(LineSegment seg, int depth)
			{
				this._upwardSeg = new LineSegment(seg);
				this.LeftDepth = depth;
			}

			public int CompareTo(SubgraphDepthLocater.DepthSegment other)
			{
				if (this._upwardSeg.MinX >= other._upwardSeg.MaxX)
				{
					return 1;
				}
				if (this._upwardSeg.MaxX <= other._upwardSeg.MinX)
				{
					return -1;
				}
				int num = this._upwardSeg.OrientationIndex(other._upwardSeg);
				if (num != 0)
				{
					return num;
				}
				num = -1 * other._upwardSeg.OrientationIndex(this._upwardSeg);
				if (num != 0)
				{
					return num;
				}
				return this._upwardSeg.CompareTo(other._upwardSeg);
			}

			private static int CompareX(LineSegment seg0, LineSegment seg1)
			{
				int num = seg0.P0.CompareTo(seg1.P0);
				if (num != 0)
				{
					return num;
				}
				return seg0.P1.CompareTo(seg1.P1);
			}

			public override string ToString()
			{
				return this._upwardSeg.ToString();
			}

			private readonly LineSegment _upwardSeg;
		}
	}
}
